package com.spl.seriallibrary.locker.handleresult.locker;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;

import com.spl.seriallibrary.bean.CommonDataBean;
import com.spl.seriallibrary.locker.CMDFactory;
import com.spl.seriallibrary.locker.HandleFactory;
import com.spl.seriallibrary.locker.ILocker;
import com.spl.seriallibrary.locker.handleresult.datatransfer.BoxDataObservable;
import com.spl.seriallibrary.locker.handleresult.datatransfer.CommonDataObservable;
import com.spl.seriallibrary.locker.handleresult.datatransfer.DataObserver;
import com.spl.seriallibrary.util.Constant;
import com.spl.seriallibrary.util.OnDataReceiverListener;
import com.spl.seriallibrary.util.SerialPortTools;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;

import com.zbyh.libserialport.LockerControl;


public class CommonLocker implements ILocker, OnDataReceiverListener {

    private LockerControl lockerControl;
    private byte[] LISHIZHI = null;
    private Context context;
    private BoxDataObservable boxDataObservable;
    private CommonDataObservable commonDataObservable;

    @SuppressLint("StaticFieldLeak")
    private static volatile CommonLocker commonLocker;

    public static CommonLocker getInstance(Context context, String devName, int baudRate) throws SecurityException, IOException{
        if (commonLocker == null) {
            synchronized (CommonLocker.class) {
                if (commonLocker == null) {
                    commonLocker = new CommonLocker(context, devName, baudRate);
                }
            }
        }
        return commonLocker;
    }

    private CommonLocker(Context context, String devName, int baudRate) throws SecurityException, IOException{
        lockerControl = new LockerControl(devName, baudRate);
        if (lockerControl.openCOM()) {
            lockerControl.setOnDataReceiverListener(this);
        }
        this.context = context;
        this.boxDataObservable = new BoxDataObservable();
        this.commonDataObservable = new CommonDataObservable();
    }

    @Override
    public int onDataReceiver(byte[] buffer, int size, int handle) {
        if (LISHIZHI == null) {
            LISHIZHI = SerialPortTools.subBytes(buffer, 0, size);
        } else {
            LISHIZHI = SerialPortTools.byteMerger(LISHIZHI, SerialPortTools.subBytes(buffer, 0, size));
        }
        int checkResultTYPE = (int) HandleFactory.produceHandle().checkData(LISHIZHI, buffer);
        if (checkResultTYPE != Constant.CheckResultTYPE.NOT_ENOUGH_LENGTH && checkResultTYPE != -1) {
            toHandle(LISHIZHI, checkResultTYPE, handle);
            LISHIZHI = null;
        }
        return checkResultTYPE;
    }


    private void toHandle(byte[] data, int checkResultTYPE, int handle) {
        switch (handle) {
            case Constant.STATE_QUERY_SINGLE_LOCK:
                if (checkResultTYPE == Constant.CheckResultTYPE.RESULT_OK) {
                    commonDataObservable.setData(new CommonDataBean(HandleFactory.produceHandle().stateQuerySingleLock(data, HandleFactory.getCurrentBoxId(), context)));
                } else if (checkResultTYPE == Constant.CheckResultTYPE.OVERTIME) {
                    commonDataObservable.setData(new CommonDataBean(null));
                }
                break;
            case Constant.STATE_OPEN_SINGLE_LOCK:
                if (checkResultTYPE == Constant.CheckResultTYPE.RESULT_OK) {
                    commonDataObservable.setData(new CommonDataBean(HandleFactory.produceHandle().stateOpenSingleLock(data, HandleFactory.getCurrentBoxId(), context)));
                } else if (checkResultTYPE == Constant.CheckResultTYPE.OVERTIME) {
                    commonDataObservable.setData(new CommonDataBean(null));
                }
                break;

            case Constant.STATE_OPEN_MUTI_LOCK:
                if (checkResultTYPE == Constant.CheckResultTYPE.OVERTIME) {
                    boxDataObservable.setIndex(99);
                }
                if (checkResultTYPE == Constant.CheckResultTYPE.RESULT_OK) {
                    boxDataObservable.addHasOpened(HandleFactory.produceHandle().stateOpenSingleLock(data, HandleFactory.getCurrentBoxId(), context));
                    boxDataObservable.setIndex(boxDataObservable.getIndex() + 1);
                }
                break;
            case Constant.STATE_QUERY_MUTI_LOCK:
                if (checkResultTYPE == Constant.CheckResultTYPE.OVERTIME) {
                    boxDataObservable.setIndex(99);
                }
                if (checkResultTYPE == Constant.CheckResultTYPE.RESULT_OK) {
                    boxDataObservable.addHasOpened(HandleFactory.produceHandle().stateQuerySingleLock(data, HandleFactory.getCurrentBoxId(), context));
                    boxDataObservable.setIndex(boxDataObservable.getIndex() + 1);
                }
                break;
            default:
                break;
        }
    }

    @Override
    public synchronized boolean openLock(String str) {
        final CountDownLatch countDownLatch = new CountDownLatch(1);
        HandleFactory.setCurrentBoxId(str);
        lockerControl.addData(CMDFactory.produceCMD().openLock(str), false, Constant.STATE_OPEN_SINGLE_LOCK);
        DataObserver dataObserver = new DataObserver();
        dataObserver.setiCommonDataObservable(new DataObserver.ICommonDataObservable() {
            @Override
            public void commonDataObservable(CommonDataObservable commonDataObservable) {
                countDownLatch.countDown();
            }
        });
        commonDataObservable.addObserver(dataObserver);
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        CommonDataBean bean = commonDataObservable.getData();
        if (bean.getO1() != null) {
            commonDataObservable.deleteObservers();
            Intent openSingleIntent = new Intent("android.intent.action.hal.iocontroller.querydata");
            openSingleIntent.putExtra("boxid", HandleFactory.getCurrentBoxId());
            openSingleIntent.putExtra("isopened", (boolean) bean.getO1());
            context.sendBroadcast(openSingleIntent);
            return (boolean) bean.getO1();
        } else {
            commonDataObservable.deleteObservers();
            return false;
        }
    }


    @Override
    public void openLock(final String[] batchboxid) {
        final CountDownLatch countDownLatch = new CountDownLatch(1);
        boxDataObservable.initData(batchboxid[0]);
        HandleFactory.setCurrentBoxId(batchboxid[0]);
        lockerControl.addData(CMDFactory.produceCMD().openLock(batchboxid[0]), false, Constant.STATE_OPEN_MUTI_LOCK);
        DataObserver dataObserver = new DataObserver();
        dataObserver.setiUpdataBox(new DataObserver.IUpdataBox() {
            @Override
            public void updataBox(BoxDataObservable boxDataObservable) {
                if (boxDataObservable.getIndex() < batchboxid.length) {
                    boxDataObservable.addbatchBoxId(batchboxid[boxDataObservable.getIndex()]);
                    HandleFactory.setCurrentBoxId(batchboxid[boxDataObservable.getIndex()]);
                    lockerControl.addData(CMDFactory.produceCMD().openLock(batchboxid[boxDataObservable.getIndex()]), false, Constant.STATE_OPEN_MUTI_LOCK);
                } else {
                    sendOpenLockResult(boxDataObservable);
                    countDownLatch.countDown();
                }
            }
        });
        boxDataObservable.addObserver(dataObserver);
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        boxDataObservable.deleteObservers();
    }

    private void sendOpenLockResult(BoxDataObservable boxDataObservable) {
        boolean[] result = new boolean[boxDataObservable.getHasOpeneds().size()];
        for (int i = 0; i < boxDataObservable.getHasOpeneds().size(); i++) {
            result[i] = boxDataObservable.getHasOpeneds().get(i);
        }
        Intent intent = new Intent("android.intent.action.hal.iocontroller.batchopen.result");
        intent.putExtra("batchboxid", boxDataObservable.getBatchBoxIds().toArray(new String[boxDataObservable.getBatchBoxIds().size()]));
        intent.putExtra("opened", result);
        context.sendBroadcast(intent);
    }


    @Override
    public synchronized void queryLock(String str) {
        final CountDownLatch countDownLatch = new CountDownLatch(1);
        HandleFactory.setCurrentBoxId(str);
        lockerControl.addData(CMDFactory.produceCMD().queryLock(str), false, Constant.STATE_QUERY_SINGLE_LOCK);
        DataObserver dataObserver = new DataObserver();
        dataObserver.setiCommonDataObservable(new DataObserver.ICommonDataObservable() {
            @Override
            public void commonDataObservable(CommonDataObservable commonDataObservable) {
                countDownLatch.countDown();
            }
        });
        commonDataObservable.addObserver(dataObserver);
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        CommonDataBean bean = commonDataObservable.getData();
        if (bean.getO1() != null) {
            Intent openSingleIntent = new Intent("android.intent.action.hal.iocontroller.querydata");
            openSingleIntent.putExtra("boxid", HandleFactory.getCurrentBoxId());
            openSingleIntent.putExtra("isopened", (boolean) bean.getO1());
            context.sendBroadcast(openSingleIntent);
        }
        commonDataObservable.deleteObservers();
    }

    @Override
    public void queryLock(final String[] batchboxid) {
        final CountDownLatch countDownLatch = new CountDownLatch(1);
        boxDataObservable.initData(batchboxid[0]);
        HandleFactory.setCurrentBoxId(batchboxid[0]);
        lockerControl.addData(CMDFactory.produceCMD().queryLock(batchboxid[0]), false, Constant.STATE_QUERY_MUTI_LOCK);
        DataObserver dataObserver = new DataObserver();
        dataObserver.setiUpdataBox(new DataObserver.IUpdataBox() {
            @Override
            public void updataBox(BoxDataObservable boxDataObservable) {
                if (boxDataObservable.getIndex() < batchboxid.length) {
                    boxDataObservable.addbatchBoxId(batchboxid[boxDataObservable.getIndex()]);
                    HandleFactory.setCurrentBoxId(batchboxid[boxDataObservable.getIndex()]);
                    lockerControl.addData(CMDFactory.produceCMD().queryLock(batchboxid[boxDataObservable.getIndex()]), false, Constant.STATE_QUERY_MUTI_LOCK);
                } else {
                    sendQueryLockResult(boxDataObservable);
                    countDownLatch.countDown();
                }
            }
        });
        boxDataObservable.addObserver(dataObserver);
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        boxDataObservable.deleteObservers();
    }

    private void sendQueryLockResult(BoxDataObservable boxDataObservable) {
        boolean[] result = new boolean[boxDataObservable.getHasOpeneds().size()];
        for (int i = 0; i < boxDataObservable.getHasOpeneds().size(); i++) {
            result[i] = boxDataObservable.getHasOpeneds().get(i);
        }
        Intent intent = new Intent("android.intent.action.hal.iocontroller.batchopen.result");
        intent.putExtra("batchboxid", boxDataObservable.getBatchBoxIds().toArray(new String[boxDataObservable.getBatchBoxIds().size()]));
        intent.putExtra("opened", result);
        context.sendBroadcast(intent);
    }

}
